//Lindsay Ergenekan 
//ergenekl@onid.oregonstate.edu 
//CS311 - 400
//Homework 6 - Twin Primes



//4,294,965,839 - goes up to here
//4,294,967,295 - largest unsigned int

#include "hw5.h"

#define ISBITSET(x,i) ((x[i>>3] & (1<<(i&7)))!=0)
#define SETBIT(x,i) x[i>>3]|=(1<<(i&7));
#define CLEARBIT(x,i) x[i>>3]&=(1<<(i&7))^0xFF;

//#define MAP_SIZE 100000

int main(int argc, char *argv[])
{

    char c;
    long i, j, k;
    pthread_attr_t attr;
    unsigned int maxNumber = UINT_MAX;

  //  unsigned int maxNumber = 5000000;

    unsigned int sq_rt;
    int printPrime = 0; 
    int numThread = 1; 
    unsigned int numCalc = maxNumber; 
    unsigned int MAP_SIZE = ((maxNumber/ 8)) + 1; //set the size to the size of the char

    //checks for printing out primes, 

    numCalc = maxNumber; //set n to UINT_MAX
    printf("numCalc (%lu) Expect \n", numCalc);
    printf("numThread (%d) Expected 2 \n", numThread);
    printf("map_size (%d) Expected  \n", MAP_SIZE);
 //   sleep(5);

/////////////////////////////////////////////////////GET THE COMMAND LINE ARGS
    while ((c = getopt(argc, argv, "n:m:p")) != -1)
    switch (c){ 
        case 'n':
            numCalc = atol(optarg); 
            break;
       case 'm':
            numThread = atoi(optarg);
              printf("numThread (%lu) \n", numThread);      
            break;
        case 'p':
            printPrime = 1;
            break;
        }


        printf("numCalc (%lu) \n", numCalc);
        printf("numThread (%lu) \n", numThread);
        printf("printPrime (%lu) \n", printPrime);

////////////////////////////////////variable for the bit map
    unsigned char *bitMAP = (unsigned char *) malloc(MAP_SIZE * sizeof (unsigned char));
    pthread_t thread[numThread]; //variable to track the thread ids
    struct thread_info t_info[numThread]; //variable to pass in the info for sieve funciton 

    SETBIT(bitMAP, 0); //mark off 1 as non-prime
    SETBIT(bitMAP, 2); //mark off 2 as non-prime

///////////////////////////////////////////////////////SET ALL THE EVENT NUMBER BITS
    i = 2; 
    for (j = i*i; j <= maxNumber; j += i)
    {
        SETBIT(bitMAP,j);    
    }
    
    
////////////////////////////////////////////////////////CREATE THE THREADS

    thread_division = 3;

    for (i = 0; i < numThread; ++i)
    {
        printf("In the thread creation for (%d) \n", i);
        t_info[i].bitMAP = bitMAP;
        t_info[i].up_to_num = numCalc; 
        t_info[i].thread_no = i; 
        pthread_mutex_init(&lock, NULL);
        pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);

        if (0 != pthread_create(&thread[i], NULL, sieve, (void*)&t_info[i]))
        {
            printf("Error in thread creation \n");
            exit(2);
        }
    }

//////////////////////////////////////////////////////////join all the threads again 
    for (i = 0; i<numThread; ++i){
    
        pthread_join(thread[i], NULL); 
    }
    
 //   printf("past the join stage\n");
 //   sq_rt = sqrt(numCalc);


/////////////////////////////////////////////////////////////read out all the twin primes
    /*
    for ( i = 3; i < (numCalc-2); ++i ){
        if (!ISBITSET(bitMAP, i) && !ISBITSET(bitMAP,(i+2))){
                printf("PRIME %lu !\n", i);
            }}
    printf("past the print stage \n");
*/


/////////////////////////////////////////////////////////read out all the bits that are not set
/*
    for ( i = 3; i < (numCalc-2); ++i ){
        if (!ISBITSET(bitMAP, i) ){
                printf("PRIME %lu !\n", i);
            }}
*/

return 0; 
}

//////////////////////////////////////////////////////FUNCTION TO SIEVE THE PRIMES
void * sieve(void *arg)
{
  //  pthread_mutex_lock(&lock);

    long i, j, sq_rt;
    long up_to_num; //varialbe to record where to end
    struct thread_info * bitMAP;
    unsigned char * map;
    bitMAP = (thread_info *) arg;
    map = bitMAP->bitMAP;
    up_to_num = bitMAP->up_to_num;
    sq_rt = sqrt(up_to_num);
    int thread_no = bitMAP->thread_no; 
    int check; 

printf("Thread division start is: (%lu) \n", thread_division);

for(;;)
{
    if(thread_division > 100)
        { 
            break; 
        }

    check = pthread_mutex_trylock(&lock);
 //   printf ("thread (%d) check did not unlock %d thread division (%d) \n", thread_no, check, thread_division);
 //   if (check == EBUSY) {
 //       printf("thread is busy");
 //   }
 //   else 
        if (check == 0)
    {
  //  pthread_mutex_lock(&lock);
 //   printf ("thread (%d) check returned %d \n", thread_no, check);
    thread_division += 2; 
    printf ("thread (%d) thread division %d \n", thread_no, thread_division);
    pthread_mutex_unlock(&lock);

     }  

 }     
//    printf ("thread (%d) thread division %d \n", thread_no, thread_division);
 /*     
     if(!ISBITSET(map,i))
        {
            for (j = i*i; j <= up_to_num; j += i)
            {
                if(!ISBITSET(map, i)){
//                    pthread_mutex_lock();
                        SETBIT(map,j); 
//                    pthread_mutex_unlock();
                }    
            }
        }

*/

/*
    for(i = thread_division; i <= sq_rt; i+=2)
    {
        if(!ISBITSET(map,i))
        {
            for (j = i*i; j <= up_to_num; j += i)
            {
                if(!ISBITSET(map, i)){
//                    pthread_mutex_lock();
                        SETBIT(map,j); 
//                    pthread_mutex_unlock();
                }    
            }
        }
    }
*/

        pthread_exit((void*)0);//exit the thread

}

